﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace JPSOFTWARE.BON.Modelos
{
    public class Criptografia
    {
        private static byte[] chave = { };
        private static byte[] iv = { 12, 34, 56, 78, 90, 102, 114, 126 };

        private static string chaveCriptografia = "juniorpacheco26";

        //Criptografa o Cookie
        public static string Criptografar(string valor)
        {
            DESCryptoServiceProvider des;
            MemoryStream ms;
            CryptoStream cs; byte[] input;

            try
            {
                des = new DESCryptoServiceProvider();
                ms = new MemoryStream();

                input = Encoding.UTF8.GetBytes(valor); chave = Encoding.UTF8.GetBytes(chaveCriptografia.Substring(0, 8));

                cs = new CryptoStream(ms, des.CreateEncryptor(chave, iv), CryptoStreamMode.Write);
                cs.Write(input, 0, input.Length);
                cs.FlushFinalBlock();

                return Convert.ToBase64String(ms.ToArray());
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //Descriptografa o cookie
        public static string Descriptografar(string valor)
        {
            DESCryptoServiceProvider des;
            MemoryStream ms;
            CryptoStream cs; byte[] input;

            try
            {
                des = new DESCryptoServiceProvider();
                ms = new MemoryStream();

                input = new byte[valor.Length];
                input = Convert.FromBase64String(valor.Replace(" ", "+"));

                chave = Encoding.UTF8.GetBytes(chaveCriptografia.Substring(0, 8));

                cs = new CryptoStream(ms, des.CreateDecryptor(chave, iv), CryptoStreamMode.Write);
                cs.Write(input, 0, input.Length);
                cs.FlushFinalBlock();

                return Encoding.UTF8.GetString(ms.ToArray());
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //O salted hash é uma das técnicas mais bacanas e 
        //seguras de se criptografar strings. Sua grande
        //vantagem é que as strings uma vez criptografadas,
        //não podem ser mais descriptografadas e sim, apenas verificada sua autenticidade.

        //Abaixo segue o código para realizar a criptografia de strings usando Salted Hash:

        //Criptografa a string
        //string criptografado = HashHelper.ComputeHash("String", HashHelper.HashMethod.mhSHA512, null);
        //Verifica se é válido
        //if(HashHelper.VerifyHash("String",HashHelper.HashMethod.mhSHA512, criptografado))
        //{ /*Tudo OK*/ }

        ///////////////////////////////////////////////////////////////////////////////
        // SAMPLE: Hashing data with salt using MD5 and several SHA algorithms.
        //
        // To run this sample, create a new Visual C# project using the Console
        // Application template and replace the contents of the Class1.cs file with
        // the code below.
        //
        // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
        // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
        // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
        // 
        // Copyright (C) 2002 Obviex(TM). All rights reserved.
        // 
        /// <summary>
        /// This class generates and compares hashes using MD5, SHA1, SHA256, SHA384, 
        /// and SHA512 hashing algorithms. Before computing a hash, it appends a
        /// randomly generated salt to the plain text, and stores this salt appended
        /// to the result. To verify another plain text value against the given hash,
        /// this class will retrieve the salt value from the hash string and use it
        /// when computing a new hash of the plain text. Appending a salt value to
        /// the hash may not be the most efficient approach, so when using hashes in
        /// a real-life application, you may choose to store them separately. You may
        /// also opt to keep results as byte arrays instead of converting them into
        /// base64-encoded strings.
        /// </summary>
        public class HashHelper
        {
            public enum HashMethod
            {
                hmSHA1,
                hmSHA256,
                mhSHA384,
                mhSHA512,
                mhDefault
            }
            /// <summary>
            /// Generates a hash for the given plain text value and returns a
            /// base64-encoded result. Before the hash is computed, a random salt
            /// is generated and appended to the plain text. This salt is stored at
            /// the end of the hash value, so it can be used later for hash
            /// verification.
            /// </summary>
            /// <param name="plainText">
            /// Plaintext value to be hashed. The function does not check whether
            /// this parameter is null.
            /// </param>
            /// <param name="hashAlgorithm">
            /// Name of the hash algorithm. Allowed values are: "MD5", "SHA1",
            /// "SHA256", "SHA384", and "SHA512" (if any other value is specified
            /// MD5 hashing algorithm will be used). This value is case-insensitive.
            /// </param>
            /// <param name="saltBytes">
            /// Salt bytes. This parameter can be null, in which case a random salt
            /// value will be generated.
            /// </param>
            /// <returns>
            /// Hash value formatted as a base64-encoded string.
            /// </returns>
            public static string ComputeHash(string plainText,
                                             HashMethod hashAlgorithm,
                                             byte[] saltBytes)
            {
                // If salt is not specified, generate it on the fly.
                if (saltBytes == null)
                {
                    // Define min and max salt sizes.
                    int minSaltSize = 4;
                    int maxSaltSize = 8;
                    // Generate a random number for the size of the salt.
                    Random random = new Random();
                    int saltSize = random.Next(minSaltSize, maxSaltSize);
                    // Allocate a byte array, which will hold the salt.
                    saltBytes = new byte[saltSize];
                    // Initialize a random number generator.
                    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
                    // Fill the salt with cryptographically strong byte values.
                    rng.GetNonZeroBytes(saltBytes);
                }
                // Convert plain text into a byte array.
                byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
                // Allocate array, which will hold plain text and salt.
                byte[] plainTextWithSaltBytes =
                        new byte[plainTextBytes.Length + saltBytes.Length];
                // Copy plain text bytes into resulting array.
                for (int i = 0; i < plainTextBytes.Length; i++)
                    plainTextWithSaltBytes[i] = plainTextBytes[i];
                // Append salt bytes to the resulting array.
                for (int i = 0; i < saltBytes.Length; i++)
                    plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];
                // Because we support multiple hashing algorithms, we must define
                // hash object as a common (abstract) base class. We will specify the
                // actual hashing algorithm class later during object creation.
                HashAlgorithm hash;

                // Initialize appropriate hashing algorithm class.
                switch (hashAlgorithm)
                {
                    case HashMethod.hmSHA1:
                        hash = new SHA1Managed();
                        break;
                    case HashMethod.hmSHA256:
                        hash = new SHA256Managed();
                        break;
                    case HashMethod.mhSHA384:
                        hash = new SHA384Managed();
                        break;
                    case HashMethod.mhSHA512:
                        hash = new SHA512Managed();
                        break;
                    case HashMethod.mhDefault:
                        hash = new MD5CryptoServiceProvider();
                        break;
                    default:
                        hash = new MD5CryptoServiceProvider();
                        break;
                }

                // Compute hash value of our plain text with appended salt.
                byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);
                // Create array which will hold hash and original salt bytes.
                byte[] hashWithSaltBytes = new byte[hashBytes.Length +
                                                    saltBytes.Length];
                // Copy hash bytes into resulting array.
                for (int i = 0; i < hashBytes.Length; i++)
                    hashWithSaltBytes[i] = hashBytes[i];
                // Append salt bytes to the result.
                for (int i = 0; i < saltBytes.Length; i++)
                    hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];
                // Convert result into a base64-encoded string.
                string hashValue = Convert.ToBase64String(hashWithSaltBytes);
                // Return the result.
                return hashValue;
            }
            /// <summary>
            /// Compares a hash of the specified plain text value to a given hash
            /// value. Plain text is hashed with the same salt value as the original
            /// hash.
            /// </summary>
            /// <param name="plainText">
            /// Plain text to be verified against the specified hash. The function
            /// does not check whether this parameter is null.
            /// </param>
            /// <param name="hashAlgorithm">
            /// Name of the hash algorithm. Allowed values are: "MD5", "SHA1", 
            /// "SHA256", "SHA384", and "SHA512" (if any other value is specified,
            /// MD5 hashing algorithm will be used). This value is case-insensitive.
            /// </param>
            /// <param name="hashValue">
            /// Base64-encoded hash value produced by ComputeHash function. This value
            /// includes the original salt appended to it.
            /// </param>
            /// <returns>
            /// If computed hash mathes the specified hash the function the return
            /// value is true; otherwise, the function returns false.
            /// </returns>
            public static bool VerifyHash(string plainText,
                                          HashMethod hashAlgorithm,
                                          string hashValue)
            {
                // Convert base64-encoded hash value into a byte array.
                byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue);
                // We must know size of hash (without salt).
                int hashSizeInBits, hashSizeInBytes;

                // Size of hash is based on the specified algorithm.
                switch (hashAlgorithm)
                {
                    case HashMethod.hmSHA1:
                        hashSizeInBits = 160;
                        break;
                    case HashMethod.hmSHA256:
                        hashSizeInBits = 256;
                        break;
                    case HashMethod.mhSHA384:
                        hashSizeInBits = 384;
                        break;
                    case HashMethod.mhSHA512:
                        hashSizeInBits = 512;
                        break;
                    case HashMethod.mhDefault:
                        hashSizeInBits = 128;
                        break;
                    default:
                        hashSizeInBits = 128;
                        break;
                }
                // Convert size of hash from bits to bytes.
                hashSizeInBytes = hashSizeInBits / 8;
                // Make sure that the specified hash value is long enough.
                if (hashWithSaltBytes.Length < hashSizeInBytes)
                    return false;
                // Allocate array to hold original salt bytes retrieved from hash.
                byte[] saltBytes = new byte[hashWithSaltBytes.Length -
                                            hashSizeInBytes];
                // Copy salt from the end of the hash to the new array.
                for (int i = 0; i < saltBytes.Length; i++)
                    saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i];
                // Compute a new hash string.
                string expectedHashString =
                            ComputeHash(plainText, hashAlgorithm, saltBytes);
                // If the computed hash matches the specified hash,
                // the plain text value must be correct.
                return (hashValue == expectedHashString);
            }
        }
    }
}
//// Criptografar Senha
//public static string CriptografarSenha(string dados, string chave)
//{
//    byte[] b = Encoding.UTF8.GetBytes(dados);
//    byte[] pw = Encoding.UTF8.GetBytes(chave);

//    RijndaelManaged rm = new RijndaelManaged();

//    PasswordDeriveBytes pdb = new PasswordDeriveBytes(chave, new MD5CryptoServiceProvider().ComputeHash(pw));
//    rm.Key = pdb.GetBytes(32);
//    rm.IV = pdb.GetBytes(16);
//    rm.BlockSize = 128;
//    rm.Padding = PaddingMode.PKCS7;

//    MemoryStream ms = new MemoryStream();
//    CryptoStream cryptStream = new CryptoStream(ms, rm.CreateEncryptor(rm.Key, rm.IV), CryptoStreamMode.Write);
//    cryptStream.Write(b, 0, b.Length);
//    cryptStream.FlushFinalBlock();
//    return System.Convert.ToBase64String(ms.ToArray());
//}